package com.ayx.mallchat.common.websocket.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.ayx.mallchat.common.websocket.domain.dto.WSChannelExtraDTO;
import com.ayx.mallchat.common.websocket.domain.enums.WSRespTypeEnum;
import com.ayx.mallchat.common.websocket.domain.vo.resp.WSBaseResp;
import com.ayx.mallchat.common.websocket.domain.vo.resp.WSLoginUrl;
import com.ayx.mallchat.common.websocket.service.WebSocketService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalUnit;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * websocket的所有操作都在此类实现
 */
@Service
public class WebSocketServiceImpl implements WebSocketService {

    @Autowired
    private WxMpService wxMpService;

    /**
     * 当连接建立时保存所有连接
     *
     * @param channel
     */
    private static final Map<Channel, WSChannelExtraDTO> ALL_ONLINE_MAP = new ConcurrentHashMap<>();


    public static final Duration DURATION = Duration.ofHours(1);
    public static final int MAXIMUM_SIZE = 10000;

    /**
     * 临时保存登录CODE和Channel的关联关系
     */
    private static final Cache<Integer, Channel> WAIT_LOGIN_MAP = Caffeine.newBuilder().maximumSize(MAXIMUM_SIZE)
            .expireAfterWrite(DURATION).build();

    @Override
    public void connect(Channel channel) {
        ALL_ONLINE_MAP.put(channel, new WSChannelExtraDTO());
    }

    /**
     * 处理登录请求
     *
     * @param channel
     */
    @Override
    public void handleLoginReq(Channel channel) throws WxErrorException {
        //生成随机CODE,并将Channel保存到map中
        Integer code = generateRandomCode(channel);
        //找微信申请二维码
        WxMpQrCodeTicket mpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) DURATION.getSeconds());
        //发送给前端
        WSBaseResp<WSLoginUrl> baseResp = new WSBaseResp<>();
        baseResp.setData(new WSLoginUrl(mpQrCodeTicket.getUrl()));
        baseResp.setType(WSRespTypeEnum.LOGIN_URL.getType());
        sendMessage(channel, baseResp);
    }

    @Override
    public void userOffline(Channel channel) {
        ALL_ONLINE_MAP.remove(channel);
        //TODO 用户下线
    }

    private void sendMessage(Channel channel, WSBaseResp baseResp) {
        channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(baseResp)));
    }

    private Integer generateRandomCode(Channel channel) {
        Integer code;
        do {
            code = RandomUtil.randomInt(Integer.MAX_VALUE);
        } while (Objects.nonNull(WAIT_LOGIN_MAP.asMap().putIfAbsent(code, channel)));
        return code;
    }

}
